package com.eliza.base.views.learn.graphics

import android.graphics.RuntimeShader
import android.graphics.Shader
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.draw.drawWithCache
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.geometry.center
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.ImageShader
import androidx.compose.ui.graphics.LinearGradientShader
import androidx.compose.ui.graphics.RadialGradientShader
import androidx.compose.ui.graphics.ShaderBrush
import androidx.compose.ui.graphics.TileMode
import androidx.compose.ui.graphics.drawscope.inset
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.imageResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.eliza.base.R
import org.intellij.lang.annotations.Language

/*
* Compose 中的 Brush 用于描述内容在屏幕上的绘制方式：它可以确定要在绘制区域（即圆形、方形、路径）中绘制的颜色。有一些内置 Brush 对绘制非常有用，例如 LinearGradient、RadialGradient 或普通的 SolidColor Brush。

Brush 可与 Modifier.background()、TextStyle 或 DrawScope 绘制调用搭配使用，以将绘制样式应用于要绘制的内容。
* */
object BrushX {
    @Composable
    fun Show() {
        var swi by remember {
            mutableIntStateOf(0)
        }
        Column {
            Button(onClick = { swi = (swi + 1) % 5 }) {
                Text(text = "Click TO Change ${swi}")
            }
            when (swi) {
                0 -> BrushX()
                1 -> TileModeX()
                2 -> CustomBrushX()
                3 -> BrushUseImgX()
                4 -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                    BrushAGSLX()
                } else {
                    Text(text = "requires API level 33 ")
                }
            }
        }
    }

    //    核心方法是使用修饰符，例如 Modifier.drawWithContent、Modifier.drawBehind 和 Modifier.drawWithCache。

    @Composable
    private fun BrushX() {
        Column(modifier = Modifier.verticalScroll(rememberScrollState())) {
            val brush = Brush.horizontalGradient(listOf(Color.Red, Color.Blue))
            Canvas(
                modifier = Modifier.size(200.dp),
                onDraw = {
                    drawCircle(brush)
                }
            )
            val colorStops = arrayOf(
                0.0f to Color.Yellow,
                0.2f to Color.Red,
                1f to Color.Blue
            )
            Box(
                modifier = Modifier
                    .requiredSize(200.dp)
                    .background(Brush.horizontalGradient(colorStops = colorStops))
            ) {
                Text(text = "colorStops 更改颜色分布")
            }

        }
    }

    @Composable
    private fun TileModeX() {
        val listColors = listOf(Color.Yellow, Color.Red, Color.Blue)
        val tileSize = with(LocalDensity.current) {
            50.dp.toPx()
        }
        var tileModex: @Composable (tileMode: TileMode) -> Unit = {
            Box(
                modifier = Modifier
                    .requiredSize(100.dp)
                    .background(
                        Brush.horizontalGradient(
                            listColors,
                            endX = tileSize,
                            tileMode = it
                        )
                    )
            )
        }


        tileModex(TileMode.Repeated)
        tileModex(TileMode.Mirror)
        tileModex(TileMode.Clamp)
        tileModex(TileMode.Decal)
    }

    //    可以扩展 Shader 并在 createShader 函数中利用绘制区域大小。
    @Composable
    private fun CustomBrushX() {
        Column(
            modifier = Modifier
                .fillMaxWidth(1f)
                .verticalScroll(rememberScrollState())
        ) {
            Text(text = "CustomBrushX")
            val listColors = listOf(Color.Yellow, Color.Red, Color.Blue)
            val customBrush = remember {
                object : ShaderBrush() {
                    override fun createShader(size: Size): Shader {
                        return LinearGradientShader(
                            colors = listColors,
                            from = Offset.Zero,
                            to = Offset(size.width / 3f, 0f),
                            tileMode = TileMode.Mirror
                        )
                    }
                }
            }
            Box(
                modifier = Modifier
                    .requiredSize(200.dp)
                    .background(customBrush)
            )
            //。如果您未指定大小和中心，渐变将占据 DrawScope 的整个边界，径向渐变的中心也将默认设置为 DrawScope 边界的中心。
            // 这会导致径向渐变的中心显示为较小维度（宽度或高度）的中心
            Text(text = "未指定大小和中心")

            Box(
                modifier = Modifier
                    .requiredSize(200.dp)
                    .background(
                        Brush.radialGradient(
                            listOf(Color(0xFF2be4dc), Color(0xFF243484))
                        )
                    )
            )

            Text(text = "径向渐变更改为将半径大小设置为最大维度")
            val largeRadialGradient = object : ShaderBrush() {
                override fun createShader(size: Size): Shader {
                    val biggerDimension = maxOf(size.width, size.width)
                    return RadialGradientShader(
                        colors = listOf(Color(0xFF2be4dc), Color(0xFF243484)),
                        center = size.center,
                        radius = biggerDimension / 2f,
                        colorStops = listOf(0f, 0.95f)
                    )
                }
            }
            Box(
                modifier = Modifier
                    .requiredSize(200.dp)
                    .background(largeRadialGradient)
            )
            /*为创建着色器而传递的实际尺寸是由调用着色器的位置决定的。
            默认情况下，如果大小与上次创建 Brush 时不同，或者创建着色器时使用的状态对象发生更改，
            Brush 会在内部重新分配其 Shader。*/
            val colorStops = arrayOf(
                0.0f to Color.Yellow,
                0.2f to Color.Red,
                1f to Color.Blue
            )
            val brush = Brush.horizontalGradient(colorStops = colorStops)
            Box(
                modifier = Modifier
                    .requiredSize(200.dp)
                    .drawBehind {
                        this.drawRect(brush = brush) // will allocate a shader to occupy the 200 x 200 dp drawing area
                        inset(10f) {
                            /* Will allocate a shader to occupy the 180 x 180 dp drawing area as the
                             inset scope reduces the drawing  area by 10 pixels on the left, top, right,
                            bottom sides */
                            drawRect(brush = brush)
                            inset(5f) {
                                /* will allocate a shader to occupy the 170 x 170 dp drawing area as the
                                 inset scope reduces the  drawing area by 5 pixels on the left, top,
                                 right, bottom sides */
                                drawRect(brush = brush)
                            }
                        }
                    }
            )
        }

    }

    @Composable
    fun BrushUseImgX() {
        Text(text = "BrushUseImgX")
        val imageBrush =
            ShaderBrush(ImageShader(ImageBitmap.imageResource(id = R.drawable.tou_xiang)))

// Use ImageShader Brush with background
        Box(
            modifier = Modifier
                .requiredSize(200.dp)
                .background(imageBrush)
        )

// Use ImageShader Brush with TextStyle
        Text(
            text = "Hello Android!",
            style = TextStyle(
                brush = imageBrush,
                fontWeight = FontWeight.ExtraBold,
                fontSize = 36.sp
            )
        )

// Use ImageShader Brush with DrawScope#drawCircle()
        Canvas(onDraw = {
            drawCircle(imageBrush)
        }, modifier = Modifier.size(200.dp))
    }

    @RequiresApi(Build.VERSION_CODES.TIRAMISU)
    @Composable
    fun BrushAGSLX() {
        @Language("AGSL")
        val CUSTOM_SHADER = """
    uniform float2 resolution;
    layout(color) uniform half4 color;
    layout(color) uniform half4 color2;

    half4 main(in float2 fragCoord) {
        float2 uv = fragCoord/resolution.xy;

        float mixValue = distance(uv, vec2(0, 1));
        return mix(color, color2, mixValue);
    }
""".trimIndent()

        val Coral = Color(0xFFF3A397)
        val LightYellow = Color(0xFFF8EE94)
        Box(
            modifier = Modifier
                .drawWithCache {
                    val shader = RuntimeShader(CUSTOM_SHADER)
                    val shaderBrush = ShaderBrush(shader)
                    shader.setFloatUniform("resolution", size.width, size.height)
                    onDrawBehind {
                        shader.setColorUniform(
                            "color",
                            android.graphics.Color.valueOf(
                                LightYellow.red, LightYellow.green,
                                LightYellow
                                    .blue,
                                LightYellow.alpha
                            )
                        )
                        shader.setColorUniform(
                            "color2",
                            android.graphics.Color.valueOf(
                                Coral.red,
                                Coral.green,
                                Coral.blue,
                                Coral.alpha
                            )
                        )
                        drawRect(shaderBrush)
                    }
                }
                .fillMaxWidth()
                .height(200.dp)
        )
    }
}